package JAVA并发;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhangmin
 * @create 2022-03-15 19:44
 *
 * 五、线程间的协作
 * join()：在线程中调用另一个线程的 join() 方法，会将当前线程挂起，而不是忙等待，直到目标线程结束。
 *
 * wait() notify() notifyAll():
 *          调用 wait() 使得线程等待某个条件满足，线程在等待时会被挂起，当其他线程的运行使得这个条件满足时，其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。
 *          只能用在同步方法或者同步控制块中使用，否则会在运行时抛出 IllegalMonitorStateException。
 *   wait() 和 sleep() 的区别
 *          wait() 是 Object 的方法，而 sleep() 是 Thread 的静态方法；
 *          wait() 会释放锁，sleep() 不会。
 *
 * await() signal() signalAll()：
 *          java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调，可以在 Condition 上调用 await() 方法使线程等待，
 *          其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。相比于 wait() 这种等待方式，await() 可以指定等待的条件，因此更加灵活。
 */
public class Join5 {
    private class A extends Thread{
        public void run(){
            System.out.println("A");
        }
    }
    private class B extends Thread{
        private A a;
        B(A a){
            this.a=a;
        }
        public void run(){
            try {
                //在B的线程中需要先完成A的线程才能继续
                a.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B");
        }
    }

    private void test(){
        A a=new A();
        B b=new B(a);
        //先启动b但是会先执行完a再继续执行b
        b.start();
        a.start();
    }

    public synchronized void before(){
        System.out.println("before");
        //执行完后唤醒所有wait的线程
        notifyAll();
    }
    public synchronized void after(){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after");
    }


    //使用 Lock 来获取一个 Condition 对象。
    private Lock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();
    private void before1(){
        lock.lock();
        try {
            System.out.println("brefore1");
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }
    private void after1(){
        lock.lock();
        try {
            condition.await();
            System.out.println("after1");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        Join5 e=new Join5();
        /*e.test();*/

        ExecutorService executorService= Executors.newCachedThreadPool();
        //先启动after，但是会先执行完before然后才执行after
        /*executorService.execute(()->e.after());
        executorService.execute(()->e.before());*/
        //使用await() signal() signalAll()：会先执行完before1后再执行after1
        executorService.execute(()->e.after1());
        executorService.execute(()->e.before1());
    }
}
